#ifndef AFCORE_COMMON_LOG_APPENDER_APPENDER_CONSOLE_
#define AFCORE_COMMON_LOG_APPENDER_APPENDER_CONSOLE_

#include <cstdio>

#include "appender.h"
#include "helper.h"
#include "nocopyable.h"
#include "sync.h"

namespace afcore {

/// @brief  日志
namespace log {

/// @brief  控制台记录器
/// @tparam ConsoleMutex        互斥锁
template<typename ConsoleMutex>
class CAppenderConsoleBase
  : public CNocopyable
  , public CAppender {
public:
  using RMutex = typename ConsoleMutex::RMutex;

  /// @brief  显示构造函数
  /// @param  file            文件句柄
  explicit CAppenderConsoleBase(FILE* file);
  /// @brief  析构函数
  ~CAppenderConsoleBase() override = default;

  /// @brief  记录
  /// @param  msg         日志信息
  void Log(const SLogMessage& msg) override;
  /// @brief  刷新
  void Flush() override;
  /// @brief  设置模式
  /// @param  pattern    模式
  void SetPattern(const std::string& pattern) override;
  /// @brief  设置格式
  /// @param  formatter   格式
  void SetFormatter(RFormatterUptr formatter) override;

protected:
  RMutex& mutex_;                         ///< 互斥锁
  FILE* file_;                            ///< 文件
  RFormatterUptr formatter_;              ///< 格式化类
};

template<typename ConsoleMutex>
class CAppenderConsoleStdout
  : public CAppenderConsoleBase<ConsoleMutex> {
public:
  CAppenderConsoleStdout();
};

template<typename ConsoleMutex>
class CAppenderConsoleStdErr
  : public CAppenderConsoleBase<ConsoleMutex> {
public:
  CAppenderConsoleStdErr();
};

using RAppenderConsoleStdout_MT = CAppenderConsoleStdout<SConsoleMutex>;
using RAppenderConsoleStdout_ST = CAppenderConsoleStdout<SConsoleNullMutex>;

using RAppenderConsoleStdErr_MT = CAppenderConsoleStdErr<SConsoleMutex>;
using RAppenderConsoleStdErr_ST = CAppenderConsoleStdErr<SConsoleNullMutex>;

} // !namespace log

using namespace log;

template<typename Factory = SSyncFactory>
std::shared_ptr<CLogger> ConsoleStdout_MT(const std::string& logger_name);

template<typename Factory = SSyncFactory>
std::shared_ptr<CLogger> ConsoleStdout_ST(const std::string& logger_name);

template<typename Factory = SSyncFactory>
std::shared_ptr<CLogger> ConsoleStderr_MT(const std::string& logger_name);

template<typename Factory = SSyncFactory>
std::shared_ptr<CLogger> ConsoleStderr_ST(const std::string& logger_name);

} // !namespace afcore

#endif //! AFCORE_COMMON_LOG_APPENDER_APPENDER_CONSOLE_